home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
Fields.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-24
|
18KB
|
846 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "Fields.h"
#include "Class.h"
#include "Look.h"
#include "GapText.h"
#include "Manager.h"
#include "RegularExp.h"
#include "Clipper.h"
#include "TextView.h"
#include "Alert_e.h"
#include "Window.h"
#include "Math.h"
//---- TextViewOverlay ---------------------------------------------------------
static TextViewOverlay *gTVO;
ONEXIT(Fields)
{
SafeDelete(gTVO);
}
TextViewOverlay::TextViewOverlay()
{
currentfield= 0;
ct= 0;
cl= 0;
tv= 0;
noupdate= FALSE;
}
TextViewOverlay::~TextViewOverlay()
{
currentfield= 0;
if (ct) {
Object *op;
Iter next(ct->GetObserverIter());
while (op= next())
ct->RemoveObserver(op);
SafeDelete(ct);
}
SafeDelete(cl);
SafeDelete(tv);
}
bool TextViewOverlay::CopyInStr(EditField *ef, char *buf, int sz)
{
if (ef == currentfield) {
ct->CopyInStr((byte*)buf, sz, 0, ct->Size());
return FALSE;
}
return TRUE;
}
bool TextViewOverlay::Size(EditField *ef, int *sz)
{
if (ef == currentfield) {
*sz= ct->End();
return FALSE;
}
return TRUE;
}
bool TextViewOverlay::KbdFocus(EditField *ef, bool in, bool wordwrap)
{
if (gDebug)
fprintf(stderr, "TextViewOverlay::KbdFocus(0x%08x, %d) old:0x%08x\n",
ef, in, currentfield);
if (in) {
if (currentfield != 0) {
if (gDebug)
fprintf(stderr, "KbdFocus(in): oops\n");
return FALSE;
}
if (ef)
ef->Reveal();
char *es= ef->GetStringForEditing();
currentfield= ef;
currentfield->SetFlag(eEditFieldHasOverlay);
if (ct == 0) {
ct= new GapText((byte*)es);
tv= new TextView(currentfield, gFitRect, ct, TRUE);
tv->SetDragAndDrop(FALSE);
tv->SetFlag(eViewNoPrint);
tv->SetStopChars("\r\n");
tv->ResetFlag(eVObjKbdFocus);
cl= new Clipper(tv);
cl->Open();
} else {
ct->ReplaceWithStr((byte*)es);
cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
}
//ct->SetFont(currentfield->GetFont(), 0, ct->Size());
ct->SetFont(currentfield->GetFont());
if (gToken.Code != eEvtLeftButton)
tv->SelectAll(FALSE);
ct->AddObserver(currentfield);
cl->SetContainer(currentfield);
tv->SetNextHandler(currentfield);
//cl->Open();
if (wordwrap)
tv->SetWordWrap(TRUE);
currentfield->SetExtent(currentfield->GetExtent());
currentfield->SetOrigin(currentfield->GetOrigin());
currentfield->ForceRedraw();
} else {
if (currentfield != ef) {
if (gDebug) {
fprintf(stderr, "KbdFocus(out): oops %d\n", currentfield);
}
return FALSE;
}
if (!Sync(currentfield))
return FALSE;
tv->SetWordWrap(FALSE);
currentfield->ForceRedraw();
cl->ClearContainer(currentfield);
ct->RemoveObserver(currentfield);
currentfield->ResetFlag(eEditFieldHasOverlay);
currentfield= 0;
}
return tv->KbdFocus(in);
}
bool TextViewOverlay::Sync(EditField *ef)
{
if (currentfield == ef) {
char *tmp= ct->AsString();
noupdate= TRUE;
bool valid= currentfield->ValidateString(tmp);
noupdate= FALSE;
delete tmp;
if (! valid) {
ct->ReplaceWithStr((byte*)currentfield->GetStringForEditing());
cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
tv->SelectAll(FALSE);
return FALSE;
}
return TRUE;
}
return FALSE;
}
bool TextViewOverlay::Draw(EditField *ef, Rectangle r)
{
if (currentfield == ef) {
cl->DrawAll(r);
return FALSE;
}
return TRUE;
}
void TextViewOverlay::Update(EditField *ef)
{
if (currentfield == ef && !noupdate) {
ct->ReplaceWithStr((byte*)currentfield->GetStringForEditing());
//if (ct->GetFont() != currentfield->GetFont())
ct->SetFont(currentfield->GetFont());
cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
}
}
void TextViewOverlay::SetOrigin(EditField *ef, Point at)
{
if (currentfield == ef)
cl->SetOrigin(at);
}
void TextViewOverlay::SetExtent(EditField *ef, Point e)
{
if (currentfield == ef) {
cl->SetExtent(e);
if (tv->GetWordWrap())
tv->SetExtent(Point(e.x, cFit));
}
}
Command *TextViewOverlay::DispatchEvents(EditField *ef, Point lp, Token &t, Clipper *vf)
{
if (currentfield == ef)
return cl->Input(lp, t, vf);
return 0;
}
void TextViewOverlay::DoSetupMenu(EditField *ef, Menu *m)
{
if (currentfield == ef)
tv->DoSetupMenu(m);
}
Command *TextViewOverlay::DoMenuCommand(EditField *ef, int c)
{
if (currentfield == ef)
return tv->DoMenuCommand(c);
return gNoChanges;
}
//---- Field ----------------------------------------------------------------
NewMetaImpl(Field,VObject, (TP(font), T(minwidth)));
Field::Field(int mw, Font *f)
{
Init(mw, f);
}
Field::Field(int id, int mw, Font *f) : VObject(id)
{
Init(mw, f);
}
void Field::Init(int mw, Font *f)
{
font= f;
minwidth= mw;
SetFlag(eVObjVFixed);
}
void Field::SetEditable(bool e)
{
SetFlag(eVObjKbdFocus, e);
SetFlag(eEditFieldNoBorder, !e);
}
char *Field::GetStringForDrawing()
{
return AsString();
}
void Field::SetFont(Font *fp)
{
font= fp;
}
Metric Field::GetMinSize()
{
int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
return StaticTextView::MeasureText(GetStringForDrawing(), font,
minwidth, GetLines()).Expand(gBorder+Point(b));
}
void Field::Draw(Rectangle)
{
int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
Ink *ink= Enabled() ? gInkBlack : gLook->DisableInk();
StaticTextView::DrawBoxedText(contentRect.Inset(gBorder+Point(b)),
GetStringForDrawing(), font, ink, GetLines() > 1);
}
int Field::Compare(Object *op)
{
char *t1= AsString(), *t2= Guard(op,Field)->AsString();
return StrCmp((byte*)t1, (byte*)t2, -1, sortmap);
}
bool Field::IsEqual(Object *op)
{
if (op == 0 || ! op->IsKindOf(Field))
return FALSE;
byte *s1= (byte*)AsString(), *s2= (byte*)op->AsString();
if (s1 == 0 || s2 == 0)
return FALSE;
return StrCmp(s1, s2, -1, sortmap) == 0;
}
int Field::GetLines()
{
return 1;
}
OStream& Field::PrintOn (OStream &s)
{
VObject::PrintOn(s);
return s << font SP << minwidth SP;
}
IStream& Field::ReadFrom(IStream &s)
{
VObject::ReadFrom(s);
return s >> font >> minwidth;
}
//---- EditField ---------------------------------------------------------------
NewMetaImpl0(EditField,Field);
EditField::EditField(int id, int mw, Font *f) : Field(id, mw, f)
{
SetFlag(eVObjEnabled | eVObjKbdFocus);
}
EditField::~EditField()
{
//if (HasOverlay())
// GetTextViewOverlay()->KbdFocus(this, FALSE, FALSE);
}
TextViewOverlay *EditField::GetTextViewOverlay()
{
Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
if (m)
return m->GetTextViewOverlay();
if (gDebug) {
fprintf(stderr, "EditField::GetTextViewOverlay\n");
if (GetNextHandler())
fprintf(stderr, "GetNextHandler(): %s\n", GetNextHandler()->ClassName());
else
fprintf(stderr, "GetNextHandler(): 0\n");
}
if (gTVO == 0)
gTVO= new TextViewOverlay;
return gTVO;
}
char *EditField::GetStringForEditing()
{
return AsString();
}
void EditField::Draw(Rectangle r)
{
if (!HasOverlay() || GetTextViewOverlay()->Draw(this, r))
Field::Draw(r);
gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->Adorn(this, r, HasOverlay());
}
void EditField::Update(bool redraw)
{
if (HasOverlay())
GetTextViewOverlay()->Update(this);
if (redraw)
InvalidateRect(contentRect.Inset(gPoint4));
//ForceRedraw();
}
void EditField::Sync()
{
if (HasOverlay())
GetTextViewOverlay()->Sync(this);
}
static bool lock;
void EditField::DoSetupMenu(Menu *m)
{
if (HasOverlay() && !lock) {
lock= TRUE;
GetTextViewOverlay()->DoSetupMenu(this, m);
lock= FALSE;
} else
Field::DoSetupMenu(m);
}
Command *EditField::DoMenuCommand(int c)
{
if (HasOverlay() && !lock) {
lock= TRUE;
Command *cmd= GetTextViewOverlay()->DoMenuCommand(this, c);
lock= FALSE;
return cmd;
}
return Field::DoMenuCommand(c);
}
Command *EditField::Input(Point lp, Token &t, Clipper *vf)
{
if (t.IsKey()) {
if (t.Code == '\t') {
Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
if (m)
m->TabFields(t);
return gNoChanges;
}
if ((t.Code == '\r' || t.Code == '\n') && GetLines() <= 1) {
Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
if (m)
m->TabFields(t);
return gNoChanges;
}
}
return Field::Input(lp, t, vf);
}
void EditField::SetOrigin(Point at)
{
Field::SetOrigin(at);
if (HasOverlay()) {
int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
GetTextViewOverlay()->SetOrigin(this, at+Point(b));
}
}
void EditField::SetExtent(Point e)
{
Field::SetExtent(e);
if (HasOverlay()) {
int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
GetTextViewOverlay()->SetExtent(this, e-2*Point(b));
}
}
bool EditField::KbdFocus(bool in)
{
if (HasOverlay() != in)
return GetTextViewOverlay()->KbdFocus(this, in, GetLines() > 1);
return TRUE;
}
void EditField::Control(int id, int part, void *val)
{
switch (part) {
case cPartSelectionChanged:
case cPartViewSize:
case cPartOriginChanged:
case cPartExtentChanged:
case cPartScrollPos:
break;
case cPartChangedText:
Field::Control(GetId(), part, val);
break;
default:
if (gDebug)
fprintf(stderr, "EditField::Control(%d, %d, %d)\n", id, part, val);
Field::Control(id, part, val);
break;
}
}
Command *EditField::DispatchEvents(Point lp, Token &t, Clipper *vf)
{
Command *cmd;
if (HasOverlay() && (cmd= GetTextViewOverlay()->DispatchEvents(this, lp, t, vf)))
return cmd;
return Field::DispatchEvents(lp, t, vf);
}
bool EditField::ValidateString(char*)
{
// called when content in TextView needs to be checked, eg. focus loss
// override for validation, reformatting and completion of string
// return FALSE if not acceptable
return TRUE;
}
void EditField::Open(bool mode)
{
Field::Open(mode);
}
//---- TextField ---------------------------------------------------------------
NewMetaImpl(TextField,EditField, (TP(text)));
TextField::TextField(int id, int minWidthInChars, Font *f) : EditField(id, 0, f)
{
text= 0;
strreplace(&text, "");
minwidth= font->Width('w') * minWidthInChars;
}
TextField::TextField(int id, int minWidthInPixel, char *t) : EditField(id, minWidthInPixel)
{
text= 0;
if (t == 0)
t= "";
strreplace(&text, t);
}
TextField::~TextField()
{
SafeDelete(text);
}
char *TextField::AsString()
{
return text;
}
void TextField::SetString(char *t, bool redraw)
{
strreplace(&text, t);
Update(redraw);
Changed();
}
void TextField::SetFString(bool redraw, char *va_(fmt), ...)
{
va_list ap;
va_start(ap,va_(fmt));
strfreplace(&text, va_(fmt), ap);
Update(redraw);
Changed();
va_end(ap);
}
void TextField::GetString(char *buf, int sz)
{
if (!HasOverlay() || GetTextViewOverlay()->CopyInStr(this, buf, sz)) {
if (text)
strn0cpy(buf, text, sz);
else
strcpy(buf, "");
}
}
char *TextField::GetString()
{
Sync();
return AsString();
}
int TextField::GetTextSize()
{
int sz= 0;
if (!HasOverlay() || GetTextViewOverlay()->Size(this, &sz))
if (text)
sz= strlen(text);
return sz;
}
OStream& TextField::PrintOn (OStream &s)
{
EditField::PrintOn(s);
return s.PrintString(text);
}
IStream& TextField::ReadFrom(IStream &s)
{
char *t;
EditField::ReadFrom(s);
s.ReadString(&t);
SetString(t, FALSE);
return s;
}
bool TextField::ValidateString(char *s)
{
SetString(s, FALSE);
return TRUE;
}
//---- MultiLineField ----------------------------------------------------------
NewMetaImpl(MultiLineField,TextField, (T(lines)));
MultiLineField::MultiLineField(int id, int l, int mw, char *t)
: TextField(id, mw, t)
{
lines= Math::Max(0, l);
}
int MultiLineField::GetLines()
{
return lines;
}
OStream& MultiLineField::PrintOn (OStream &s)
{
TextField::PrintOn(s);
return s << lines SP;
}
IStream& MultiLineField::ReadFrom(IStream &s)
{
TextField::ReadFrom(s);
return s >> lines;
}
//---- FormatField -------------------------------------------------------------
NewMetaImpl(FormatField,EditField, (TP(format)));
FormatField::FormatField(int id, char *fmt) : EditField(id)
{
format= strsave(fmt);
}
FormatField::~FormatField()
{
SafeDelete(format);
}
OStream& FormatField::PrintOn(OStream &s)
{
EditField::PrintOn(s);
return s.PrintString(format);
}
IStream& FormatField::ReadFrom(IStream &s)
{
EditField::ReadFrom(s);
SafeDelete(format);
return s.ReadString(&format);
}
//---- IntField ----------------------------------------------------------------
NewMetaImpl(IntField,FormatField, (T(value), T(minVal), T(maxVal)));
IntField::IntField(int id, int mi, int ma, char *fmt) : FormatField(id, fmt)
{
Init(0, mi, ma);
}
IntField::IntField(int id, int val, int mi, int ma, char *fmt) : FormatField(id, fmt)
{
Init(val, mi, ma);
}
void IntField::Init(int val, int mi, int ma)
{
minVal= mi;
maxVal= ma;
int lmin= font->Width((byte*)form(format, minVal));
int lmax= font->Width((byte*)form(format, maxVal));
minwidth= Math::Max(lmin, lmax);
SetValue(val, FALSE);
}
char *IntField::AsString()
{
return form(format, value);
}
char *IntField::GetStringForDrawing()
{
return form(format, value);
}
int IntField::GetValue()
{
Sync();
return value;
}
bool IntField::SetValue(int newVal, bool redraw)
{
newVal= Math::Range(minVal, maxVal, newVal);
if (newVal != value) {
value= newVal;
Update(redraw);
return TRUE;
}
return FALSE;
}
void IntField::GetRange(int &mi, int &ma)
{
mi= minVal;
ma= maxVal;
}
void IntField::SetRange(int mi, int ma)
{
minVal= mi;
maxVal= ma;
SetValue(value);
}
OStream& IntField::PrintOn(OStream &s)
{
FormatField::PrintOn(s);
return s << value SP << minVal SP << maxVal SP;
}
IStream& IntField::ReadFrom(IStream &s)
{
int newval;
FormatField::ReadFrom(s);
s >> newval >> minVal >> maxVal;
SetValue(newval, FALSE);
return s;
}
bool IntField::ValidateString(char *s)
{
int newval;
if (sscanf(s, "%d", &newval) != 1) {
ShowAlert(eAlertNote, "\"%s\" is not a number", s);
return FALSE;
}
if (newval < minVal || newval > maxVal) {
ShowAlert(eAlertNote, "%d not in range %d-%d", newval, minVal, maxVal);
return FALSE;
}
if (SetValue(newval))
Control(GetId(), cPartValueChanged, &newval);
return TRUE;
}
//---- FloatField ----------------------------------------------------------------
NewMetaImpl(FloatField,FormatField, (T(value), T(minVal), T(maxVal)));
FloatField::FloatField(int id, double mi, double ma, char *fmt) : FormatField(id, fmt)
{
Init(0.0, mi, ma);
}
FloatField::FloatField(int id, double val, double mi, double ma, char *fmt)
: FormatField(id, fmt)
{
Init(val, mi, ma);
}
void FloatField::Init(double val, double mi, double ma)
{
minVal= mi;
maxVal= ma;
int lmin= font->Width((byte*)form(format, minVal));
int lmax= font->Width((byte*)form(format, maxVal));
minwidth= Math::Max(lmin, lmax);
SetValue(val, FALSE);
}
char *FloatField::AsString()
{
return form(format, value);
}
char *FloatField::GetStringForDrawing()
{
return form(format, value);
}
double FloatField::GetValue()
{
Sync();
return value;
}
bool FloatField::SetValue(double newVal, bool redraw)
{
newVal= Math::Range(minVal, maxVal, newVal);
if (newVal != value) {
value= newVal;
Update(redraw);
return TRUE;
}
return FALSE;
}
void FloatField::GetRange(double &mi, double &ma)
{
mi= minVal;
ma= maxVal;
}
void FloatField::SetRange(double mi, double ma)
{
minVal= mi;
maxVal= ma;
SetValue(value);
}
OStream& FloatField::PrintOn(OStream &s)
{
FormatField::PrintOn(s);
return s << value SP << minVal SP << maxVal SP;
}
IStream& FloatField::ReadFrom(IStream &s)
{
double newval;
FormatField::ReadFrom(s);
s >> newval >> minVal >> maxVal;
SetValue(newval, FALSE);
return s;
}
bool FloatField::ValidateString(char *s)
{
double newval;
if (sscanf(s, "%lf", &newval) != 1) {
ShowAlert(eAlertNote, "\"%s\" is not a number", s);
return FALSE;
}
if (newval < minVal || newval > maxVal) {
ShowAlert(eAlertNote, "%g not in range %g-%g", newval, minVal, maxVal);
return FALSE;
}
if (SetValue(newval))
Control(GetId(), cPartValueChanged, &newval);
return TRUE;
}
//---- RegExpField ----------------------------------------------------------
NewMetaImpl(RegExpField,TextField, (TP(regex), TP(errmsg)));
RegExpField::RegExpField(int id, RegularExp *r, int mw, char *msg, char *t)
: TextField(id, mw, t)
{
regex= r;
if (msg == 0)
msg= "Illegal format \"%s\" ";
errmsg= 0;
strreplace(&errmsg, msg);
}
RegExpField::~RegExpField()
{
SafeDelete(regex);
SafeDelete(errmsg);
}
bool RegExpField::ValidateString(char *s)
{
TextField::ValidateString(s);
if (strlen(s) && regex->Match(s) != strlen(s)) {
ShowAlert(eAlertNote, errmsg, s);
return FALSE;
}
return TRUE;
}
OStream& RegExpField::PrintOn(OStream &s)
{
TextField::PrintOn(s);
s << regex SP;
return s.PrintString(errmsg);
}
IStream& RegExpField::ReadFrom(IStream &s)
{
TextField::ReadFrom(s);
s >> regex;
SafeDelete(errmsg);
return s.ReadString(&errmsg);
}